package v1

import (
	"context"
	"fmt"
	Redis "github.com/felixrobcoding/go-common/redis"
	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
	"maya-service/bll"
	"maya-service/bll/weixin"
	log "maya-service/collector/logger"
	"maya-service/collector/trace_log"
	"maya-service/event"
	"maya-service/model"
	modelEvent "maya-service/model/event"
	"maya-service/model/po"
	"maya-service/server/web/middleware"
	"maya-service/store/mysql"
	"maya-service/store/redis"
	"maya-service/utils"
	"maya-service/utils/request"
	"time"
)

var Order = &order{}

func init() {
	RegisterRouter(Order)
}

type order struct{}

// Init
func (a *order) Init(r *gin.RouterGroup) {
	g := r.Group("/order", middleware.Auth())
	{
		g.POST("/create", a.create)
		g.POST("/update", a.update)
		g.POST("/list", a.list)
		g.POST("/delete", a.delete)
		g.POST("/detail", a.find)
		g.POST("/cancelOrder", a.cancelOrder)
	}

	g1 := r.Group("/order")
	{
		g1.POST("/orderList", a.orderList)
		g1.POST("/orderDetail", a.orderDetail)
		g1.POST("/grabOrder", a.grabOrder)
	}
	g2 := r.Group("/auth")
	{
		g2.POST("/signature", a.signature)
	}

	g3 := r.Group("/aiConsult")
	{
		g3.POST("/consultDetail", a.consultDetail)
	}

}

// consultDetail 咨询详情
func (a *order) consultDetail(c *gin.Context) {
	var (
		in  = &po.ConsultDetailReq{}
		err error
	)

	if err = c.ShouldBindJSON(in); err != nil {
		c.Error(err)
	}

	// 根据externalUserId 获取咨询订单
	// 获取unionId
	unionId := weixin.GetUserBaseInfo(in.ExternalUserId)
	if unionId == "" {
		c.Error(fmt.Errorf("unionId不存在"))
		return
	}

	// 获取订单信息
	orderStatus := 1
	list, _ := bll.Order.List(context.Background(), &model.OrderListRequest{
		CustomerId:  &unionId,
		OrderStatus: &orderStatus,
		Index:       1,
		Size:        1,
	})

	if len(list.List) <= 0 {
		c.Error(fmt.Errorf("订单信息不存在"))
		return
	}

	consultId := utils.StrToInt64(list.List[0].ExtraData)

	// 咨询详情
	find, err := bll.AiConsult.Find(c.Request.Context(), &model.AiConsultInfoRequest{
		Id: consultId,
	})
	if err != nil {
		return
	}

	utils.ResponseOk(c, find)
	return
}

// cancelOrder 取消订单
func (a *order) signature(c *gin.Context) {
	var (
		in  = &po.SignatureReq{}
		err error
	)

	if err = c.ShouldBindJSON(in); err != nil {
		c.Error(err)
		return
	}

	noncestr, timestamp, signature := weixin.GetSignature(in.Url)

	utils.ResponseOk(c, &po.SignatureRsp{
		Noncestr:  noncestr,
		Timestamp: timestamp,
		Signature: signature,
	})
}

// cancelOrder 取消订单
func (a *order) cancelOrder(c *gin.Context) {
	var (
		in  = &po.CancelOrderReq{}
		err error
	)

	if err = c.ShouldBindJSON(in); err != nil {
		c.Error(err)
		return
	}

	if in.UserId == "" {
		userId, err := request.GetUserId(c.Request.Context())
		if err != nil {
			c.Error(err)
			return
		}
		in.UserId = userId
	}

	// 查询订单
	info, err := bll.OrderCacheInstance.GetOrderInfo(in.OrderNo)
	if err != nil || info.Id <= 0 {
		utils.ResponseOk(c, nil)
		return
	}

	if info.CustomerId != in.UserId {
		utils.ResponseOkWithError(c, "不是你的订单，不能进行取消")
		return
	}

	if info.OrderStatus == 1 {
		utils.ResponseOkWithError(c, "订单已经被接单，不能进行取消")
		return
	}

	// 更新订单状态
	orderStatus := 4
	err = bll.Order.Update(c.Request.Context(), &model.OrderUpdateRequest{
		Id:          info.Id,
		OrderStatus: &orderStatus,
	})
	if err != nil {
		utils.ResponseOkWithError(c, err.Error())
		return
	}

	// 发送抢单成功通知
	event.Publish(c.Request.Context(), event.GrabOrderSuccess, &modelEvent.GrabOrderSuccess{
		OrderNo:  in.OrderNo,
		GrabUser: in.UserId,
	})

	utils.ResponseOk(c, nil)
	return
}

// grabOrder 抢单
func (a *order) grabOrder(c *gin.Context) {
	var (
		in  = &po.GrabOrderReq{}
		err error
	)

	if err = c.ShouldBindJSON(in); err != nil {
		c.Error(err)
		return
	}

	log.Info("######## grabOrder Req", zap.Any("data", utils.ToJsonString(in)))

	// 用户校验
	level, err := bll.GetSupervisorData(in.UserId)
	if err != nil || level == "" {
		utils.ResponseOkWithError(c, "您还不是督导师，麻烦成为督导师再来！！！")
		return
	}

	// 订单状态校验
	info, err := bll.OrderCacheInstance.GetOrderInfo(in.OrderNo)
	if err != nil || info.Id <= 0 {
		utils.ResponseOkWithError(c, "订单不存在")
		return
	}

	if info.OrderStatus != 0 {
		utils.ResponseOkWithError(c, "订单已经被抢光了")
		return
	}

	// 用户身份等级和订单等级校验
	prouctLevel := int64(info.OrderData.Goods.ProductType)
	if utils.StrToInt64(level) != int64(info.OrderData.Goods.ProductType) {
		utils.ResponseOkWithError(c, "您还不是"+fmt.Sprintf("%v", prouctLevel)+"级督导师，麻烦成为"+fmt.Sprintf("%v", prouctLevel)+"级督导师再来！！！")
		return
	}

	// 上分布式锁
	lock := Redis.TRedLock{}
	bSuccess, err := lock.Lock(redis.KV, fmt.Sprintf("grab_%v", in.OrderNo), time.Second*10)
	if err != nil || !bSuccess {
		return
	}
	defer lock.UnLock(redis.KV)

	err = mysql.OrderGrab.ExecTransaction(c.Request.Context(), func(ctx context.Context) error {
		// 创建抢单记录
		err = bll.OrderGrab.Create(ctx, &model.OrderGrabCreateRequest{
			OrderId:  in.OrderNo,
			UserId:   in.UserId,
			GrabTime: time.Now().Unix(),
			Status:   0,
		})
		if err != nil {
			return err
		}
		// 更新订单状态
		orderStatus := 1
		err = bll.Order.Update(ctx, &model.OrderUpdateRequest{
			Id:          info.Id,
			OrderStatus: &orderStatus,
		})
		return err
	})
	if err != nil {
		utils.ResponseOkWithError(c, "抢单失败")
		return
	}
	log.Info("######## 用户抢单成功", zap.Any("data", utils.ToJsonString(&modelEvent.GrabOrderSuccess{
		OrderNo:  in.OrderNo,
		GrabUser: in.UserId,
	})))

	trace_log.DebugLogger(in.OrderNo, "########## 抢单成功 GrabUserId:", in.UserId)

	// 发送抢单成功通知
	event.Publish(c.Request.Context(), event.GrabOrderSuccess, &modelEvent.GrabOrderSuccess{
		OrderNo:  in.OrderNo,
		GrabUser: in.UserId,
	})
	utils.ResponseOk(c, nil)
	return
}

// orderDetail 订单详情
func (a *order) orderDetail(c *gin.Context) {
	var (
		in  = &po.OrderDetailReq{}
		err error
	)

	if err = c.ShouldBindJSON(in); err != nil {
		c.Error(err)
		return
	}

	info, err := bll.OrderCacheInstance.GetOrderInfo(in.OrderNo)
	if err != nil {
		utils.ResponseOkWithError(c, "订单不存在")
		return
	}

	utils.ResponseOk(c, info)
	return

}

// orderList 订单列表
func (a *order) orderList(c *gin.Context) {
	var (
		err error
	)

	list, err := bll.OrderCacheInstance.GetOrderList()
	if err != nil {
		c.Error(err)
		return
	}

	utils.ResponseOk(c, list)
	return
}

// create
func (a *order) create(c *gin.Context) {
	var (
		in  = &model.OrderCreateRequest{}
		err error
	)

	if err = c.ShouldBindJSON(in); err != nil {
		c.Error(err)
		return
	}

	if err = bll.Order.Create(c.Request.Context(), in); err != nil {
		c.Error(err)
		return
	}
	utils.ResponseOk(c, nil)
}

// update
func (a *order) update(c *gin.Context) {
	var (
		in  = &model.OrderUpdateRequest{}
		err error
	)

	if err = c.ShouldBindJSON(in); err != nil {
		c.Error(err)
		return
	}

	if err = bll.Order.Update(c.Request.Context(), in); err != nil {
		c.Error(err)
		return
	}
	utils.ResponseOk(c, nil)
}

// list
func (a *order) list(c *gin.Context) {
	var (
		in  = &model.OrderListRequest{}
		out = &model.OrderListResponse{}
		err error
	)

	if err = c.ShouldBindJSON(in); err != nil {
		c.Error(err)
		return
	}

	if out, err = bll.Order.List(c.Request.Context(), in); err != nil {
		c.Error(err)
		return
	}
	utils.ResponseOk(c, out)
}

// list
func (a *order) find(c *gin.Context) {
	var (
		in  = &model.OrderInfoRequest{}
		out = &model.OrderInfo{}
		err error
	)

	if err = c.ShouldBindJSON(in); err != nil {
		c.Error(err)
		return
	}

	if out, err = bll.Order.Find(c.Request.Context(), in); err != nil {
		c.Error(err)
		return
	}
	utils.ResponseOk(c, out)
}

// delete
func (a *order) delete(c *gin.Context) {
	var (
		in  = &model.OrderDeleteRequest{}
		err error
	)

	if err = c.ShouldBindJSON(in); err != nil {
		c.Error(err)
		return
	}

	if err = bll.Order.Delete(c.Request.Context(), in); err != nil {
		c.Error(err)
		return
	}
	utils.ResponseOk(c, nil)
}
